#include "../src/myEigen.h"

#include "gtest/gtest.h"
#include <math.h>

using namespace myEigen;

TEST(Vector4Test, myEigen_Test) {
	const Vector4<float> v0;
	const Vector4<float> v1(v0);
	const Vector4<float> v2(1);
	const Vector4<float> v3(1, 2, 3, 4);
	const Vector4<float> v4(5, 6, 7, 8);
	Vector4<float> va, vb;

	EXPECT_TRUE(va == v0);
	EXPECT_TRUE(v1 == v0);
	EXPECT_TRUE(v0 == Vector4<float>(0, 0, 0, 0));
	EXPECT_TRUE(v2 == Vector4<float>(1, 1, 1, 1));
	EXPECT_TRUE(v2 + v3 == Vector4<float>(2, 3, 4, 5));
	EXPECT_TRUE(v2 - v3 == Vector4<float>(0, -1, -2, -3));

	va = v2;
	vb = v3;
	va += vb;
	EXPECT_TRUE(va == Vector4<float>(2,3,4,5));

	va = v2;
	vb = v3;
	va -= vb;
	EXPECT_TRUE(v2 == Vector4<float>(1));
	EXPECT_TRUE(-v3 == Vector4<float>(-1,-2,-3,-4));
	EXPECT_TRUE(v3 * 2 == Vector4<float>(2, 4, 6, 8));
	EXPECT_TRUE(2 * v3 == Vector4<float>(2, 4, 6, 8));
	EXPECT_TRUE(v3 * v4 == Vector4<float>(5, 12, 21, 32));
	EXPECT_TRUE(v4 * v3 == Vector4<float>(5, 12, 21, 32));
	va = v3;
	va *= v4;
	EXPECT_TRUE(va == Vector4<float>(5, 12, 21, 32));
	EXPECT_TRUE(v3 / 2 == Vector4<float>(0.5, 1, 1.5, 2));

	EXPECT_TRUE(v3.Norm() == 1 + 4 + 9 + 16);
	float len = static_cast<float>(std::sqrt(30));
	EXPECT_TRUE(v3.Length() == len);
	
	va = Vector4<float>(3,4,0,0);
	vb = Vector4<float>(va) / 5;
	va.Normalize();
	EXPECT_TRUE(va == vb);
}


TEST(Matrixf3x3Test, myEigen_Test) {
	const Matrixf3x3 I;
	float arr[3][3] = { 
		{1,0,0},
		{0,1,0},
		{0,0,1}
	};
	Matrixf3x3 mat1(arr);
	Matrixf3x3 mat2(
		1, 0, 0,
		0, 1, 0,
		0, 0, 1
	);
	const Matrixf3x3 mat3(
		Vector3f{ 1,2,3 },
		Vector3f{ 4,5,6 },
		Vector3f{ 7,8,9 }
	);
	const Matrixf3x3 mat4(
		1, 2, 3,
		4, 5, 6,
		7, 8, 9
	);

	const Matrixf3x3 mat5(
		-1, 8, 0,
		0, 3, 5,
		1, 9, 4
	);

	EXPECT_TRUE(mat1 == I);
	EXPECT_TRUE(mat2 == I);
	EXPECT_TRUE(MatrixIsIdentity(mat1));
	EXPECT_TRUE(mat3 != I);
	EXPECT_TRUE(mat3 == Matrixf3x3(
		1, 4, 7,
		2, 5, 8,
		3, 6, 9)
	);
	EXPECT_TRUE(mat3 != mat4);
	EXPECT_TRUE(mat3 == Matrix3x3Transpose(mat4));
	EXPECT_TRUE(mat3 + mat4 == Matrixf3x3(
		2,  6,  10,
		6,  10, 14,
		10, 14, 18)
	);

	EXPECT_TRUE(mat3 * Vector3f(1, 5, 9) == Vector3f(84, 99, 114));

	EXPECT_EQ(Matrix3x3Determinant(mat5), 73);
}

TEST(Matrixf4x4Test, myEigen_Test) {
	const Matrixf4x4 I;
	float arr[4][4] = {
		{1,0,0,0},
		{0,1,0,0},
		{0,0,1,0},
		{0,0,0,1} 
	};
	Matrixf4x4 mat1(arr);
	Matrixf4x4 mat2(
		1,0,0,0,
		0,1,0,0,
		0,0,1,0,
		0,0,0,1
	);
	const Matrixf4x4 mat3(
		Vector4f{ 1,  2,  3,  4 },
		Vector4f{ 5,  6,  7,  8 },
		Vector4f{ 9,  10, 11, 12 },
		Vector4f{ 13, 14, 15, 16 }
	);
	const Matrixf4x4 mat4(
		1,  2,  3,  4,
		5,  6,  7,  8,
		9,  10, 11, 12,
		13, 14, 15, 16
	);

	const Matrixf4x4 mat5(
		1, 10, 0, 0,
		0, 1, 5, 0,
		0, 3, 4, 0,
		8, 0, 0, 2
	);

	EXPECT_TRUE(mat1 == I);
	EXPECT_TRUE(mat2 == I);
	EXPECT_TRUE(MatrixIsIdentity(mat1));
	EXPECT_TRUE(mat3 != I);
	EXPECT_TRUE(mat3 == Matrixf4x4(
		1, 5, 9, 13,
		2, 6, 10, 14,
		3, 7, 11, 15,
		4, 8, 12, 16)
	);
	EXPECT_TRUE(mat3 != mat4);
	EXPECT_TRUE(mat3 == Matrix4x4Transpose(mat4));

	EXPECT_TRUE((mat3 + mat4) == Matrixf4x4(
		2,  7,  12, 17,
		7,  12, 17, 22,
		12, 17, 22, 27,
		17, 22, 27, 32)
	);

	EXPECT_TRUE(mat3 * Vector4f(1,2,3,4) == Vector4f(90, 100, 110, 120));
	EXPECT_TRUE(mat3 * mat4 == Matrixf4x4(
		276, 304, 332, 360,
		304, 336, 368, 400,
		332, 368, 404, 440,
		360, 400, 440, 480)
	);
	EXPECT_TRUE(mat3 * 2 == Matrixf4x4(
		2, 10, 18, 26,
		4, 12, 20, 28,
		6, 14, 22, 30,
		8, 16, 24, 32)
	);
	EXPECT_TRUE((mat3 * 2) == (2 * mat3));
	EXPECT_EQ(Matrix4x4Determinant(I), 1);
	EXPECT_EQ(Matrix4x4Determinant(mat3), 0);
	EXPECT_EQ(Matrix4x4Determinant(mat5), -22);

	/// online matrix calculator 
	/// https://www.bchrt.com/tools/matrix-calculator/
	EXPECT_TRUE(Matrix4x4Inverse(mat5) == Matrixf4x4(
		1, 3.63636363636363648,    -4.5454545454545456,   0,
		0, -0.363636363636363648,  0.45454545454545456,   0,
		0, 0.272727272727272736,   -0.090909090909090912, 0,
		-4, -14.54545454545454592, 18.1818181818181824,   0.5
	));

}